package net.chenlin.dp.ids.client.config;

import net.chenlin.dp.ids.client.util.AntPathUtil;
import net.chenlin.dp.ids.client.util.XmlUtil;
import net.chenlin.dp.ids.common.constant.IdsConst;
import net.chenlin.dp.ids.common.util.CommonUtil;
import net.chenlin.dp.ids.common.util.WebUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.List;

/**
 * passport客户端配置
 * @author zcl<yczclcn@163.com>
 */
@Configuration
@ConfigurationProperties(prefix = PassportClientConfig.PREFIX)
public class PassportClientConfig implements InitializingBean {

    static final String PREFIX = "ids.client";

    /**
     * 接入系统首页
     */
    private String serverName;

    /**
     * 接入应用标识
     */
    private String appCode;

    /**
     * 接入应用类型：web（默认） 或 app
     */
    private String clientType;

    /**
     * ids服务地址
     */
    private String authServerUrl;

    /**
     * authIdCookie名称
     */
    private String authIdCookieName;

    /**
     * authIdCookie的域
     */
    private String cookieDomain;

    /**
     * 默认访问策略
     */
    private String defaultAccessPolicy;

    /**
     * 匿名访问地址集合
     */
    private List<String> anonUrlList;

    /**
     * 授权访问地址集合
     */
    private List<String> authUrlList;

    /**
     * 路由访问地址集合
     */
    private List<String> routerUrlList;

    /**
     * constructor
     */
    public PassportClientConfig() { }

    /**
     * getter for serverName
     * @return
     */
    public String getServerName() {
        return serverName;
    }

    /**
     * setter for serverName
     * @param serverName
     */
    public void setServerName(String serverName) {
        this.serverName = serverName;
    }

    /**
     * getter for appCode
     * @return
     */
    public String getAppCode() {
        return appCode;
    }

    /**
     * setter for appCode
     * @param appCode
     */
    public void setAppCode(String appCode) {
        this.appCode = appCode;
    }

    /**
     * getter for clientType
     * @return
     */
    public String getClientType() {
        return clientType;
    }

    /**
     * setter for clientType
     * @param clientType
     */
    public void setClientType(String clientType) {
        this.clientType = clientType;
    }

    /**
     * getter for authServerUrl
     * @return
     */
    public String getAuthServerUrl() {
        return authServerUrl;
    }

    /**
     * setter for authServerUrl
     * @param authServerUrl
     */
    public void setAuthServerUrl(String authServerUrl) {
        this.authServerUrl = authServerUrl;
    }

    /**
     * getter for authIdCookieName
     * @return
     */
    public String getAuthIdCookieName() {
        return authIdCookieName;
    }

    /**
     * setter for authIdCookieName
     * @param authIdCookieName
     */
    public void setAuthIdCookieName(String authIdCookieName) {
        this.authIdCookieName = authIdCookieName;
    }

    /**
     * getter for cookieDomain
     * @return
     */
    public String getCookieDomain() {
        return cookieDomain;
    }

    /**
     * setter for cookieDomain
     * @param cookieDomain
     */
    public void setCookieDomain(String cookieDomain) {
        this.cookieDomain = cookieDomain;
    }

    /**
     * getter for anonUrlList
     * @return
     */
    public List<String> getAnonUrlList() {
        return anonUrlList;
    }

    /**
     * setter for anonUrlList
     * @param anonUrlList
     */
    public void setAnonUrlList(List<String> anonUrlList) {
        this.anonUrlList = anonUrlList;
    }

    /**
     * getter for defaultAccessPolicy
     * @return
     */
    public String getDefaultAccessPolicy() {
        return defaultAccessPolicy;
    }

    /**
     * setter for defaultAccessPolicy
     * @param defaultAccessPolicy
     */
    public void setDefaultAccessPolicy(String defaultAccessPolicy) {
        this.defaultAccessPolicy = defaultAccessPolicy;
    }

    /**
     * getter for authUrlList
     * @return
     */
    public List<String> getAuthUrlList() {
        return authUrlList;
    }

    /**
     * setter for authUrlList
     * @param authUrlList
     */
    public void setAuthUrlList(List<String> authUrlList) {
        this.authUrlList = authUrlList;
    }

    /**
     * getter for routerUrlList
     * @return
     */
    public List<String> getRouterUrlList() {
        return routerUrlList;
    }

    /**
     * setter for routerUrlList
     * @param routerUrlList
     */
    public void setRouterUrlList(List<String> routerUrlList) {
        this.routerUrlList = routerUrlList;
    }

    /**
     * add anonUrl
     * @param url
     */
    public void addAnonUrl(String url) {
        if (null == anonUrlList || anonUrlList.isEmpty()) {
            anonUrlList = new ArrayList<>();
        }
        anonUrlList.add(url);
    }

    /**
     * add authUrl
     * @param url
     */
    public void addAuthUrl(String url) {
        if (null == authUrlList || authUrlList.isEmpty()) {
            authUrlList = new ArrayList<>();
        }
        authUrlList.add(url);
    }

    /**
     * add routerUrl
     * @param url
     */
    public void addRouterUrl(String url) {
        if (null == routerUrlList || routerUrlList.isEmpty()) {
            routerUrlList = new ArrayList<>();
        }
        routerUrlList.add(url);
    }

    /**
     * 是否为匿名访问地址
     * @param reqUrl
     * @return
     */
    public boolean isAnonUrl(String reqUrl) {
        return AntPathUtil.doMatch(anonUrlList, reqUrl);
    }

    /**
     * 是否为授权地址
     * @param reqUrl
     * @return
     */
    public boolean isAuthUrl(String reqUrl) {
        return AntPathUtil.doMatch(authUrlList, reqUrl);
    }

    /**
     * 是否为路由地址
     * @param reqUrl
     * @return
     */
    public boolean isRouterUrl(String reqUrl) {
        return AntPathUtil.doMatch(routerUrlList, reqUrl);
    }

    /**
     * 匹配访问策略
     * @param reqUrl
     * @return
     */
    public String matchAccessPolicy(String reqUrl) {
        if (isAnonUrl(reqUrl)) {
            return IdsConst.ANON_ACCESS_POLICY;
        } else if (isAuthUrl(reqUrl)) {
            return IdsConst.AUTH_ACCESS_POLICY;
        } else if (isRouterUrl(reqUrl)) {
            return IdsConst.ROUTER_ACCESS_POLICY;
        } else {
            return defaultAccessPolicy;
        }
    }

    /**
     * 拼接登录重定向地址
     * @param redirectUrl
     * @return
     */
    public String getServLoginUrl(String redirectUrl) {
        String baseUrl = this.authServerUrl + IdsConst.LOGIN_URL;
        if (CommonUtil.strIsEmpty(redirectUrl)) {
            redirectUrl = this.getServerName();
        }
        return WebUtil.requestAppendParam(baseUrl, new String[]{IdsConst.REDIRECT_KEY}, new Object[]{redirectUrl});
    }

    /**
     * 登出地址拼接
     * @return
     */
    public String getServLogoutUrl() {
        return this.authServerUrl.concat(IdsConst.LOGOUT_URL);
    }

    /**
     * 服务端session校验地址
     * @return
     */
    public String getServAuthStatusUrl() {
        return this.authServerUrl.concat("/client").concat(IdsConst.AUTH_STATUS_URL);
    }

    /**
     * 服务端session刷新地址
     * @return
     */
    public String getServAuthRefreshUrl() {
        return this.authServerUrl.concat("/client").concat(IdsConst.AUTH_REFRESH_URL);
    }

    /**
     * 服务端session删除地址
     * @return
     */
    public String getServAuthRemoveUrl() {
        return this.authServerUrl.concat("/client").concat(IdsConst.AUTH_REMOVE_URL);
    }

    /**
     * to string
     * @return
     */
    @Override
    public String toString() {
        return "PassportClientConfig{" +
                "serverName='" + serverName + '\'' +
                ", appCode='" + appCode + '\'' +
                ", clientType='" + clientType + '\'' +
                ", authServerUrl='" + authServerUrl + '\'' +
                ", authIdCookieName='" + authIdCookieName + '\'' +
                ", cookieDomain='" + cookieDomain + '\'' +
                ", defaultAccessPolicy='" + defaultAccessPolicy + '\'' +
                ", anonUrlList='" + anonUrlList + '\'' +
                ", authUrlList='" + authUrlList + '\'' +
                ", routerUrlList='" + routerUrlList + '\'' +
                '}';
    }

    /**
     * 读取ids-access-policy.xml
     */
    @Override
    public void afterPropertiesSet() {
        XmlUtil xml = XmlUtil.getInstance("ids-access-policy.xml", "access-policy");
        // 默认authStatus匿名访问
        this.addAnonUrl("/**".concat(IdsConst.AUTH_STATUS_URL));
        // 默认访问策略
        this.setDefaultAccessPolicy(xml.getStr("default-access-policy"));
        // 匿名访问
        initAccessPolicy(xml, IdsConst.ANON_ACCESS_POLICY);
        // 授权访问
        initAccessPolicy(xml, IdsConst.AUTH_ACCESS_POLICY);
        // 路由访问
        initAccessPolicy(xml, IdsConst.ROUTER_ACCESS_POLICY);
    }

    /**
     * 初始化访问策略
     * @param policy
     */
    private void initAccessPolicy(XmlUtil xml, String policy) {
        String policyTag = policy.replace("_", "-").toLowerCase().concat("/url-pattern");
        NodeList nodeList = xml.getList(policyTag);
        for (int i = 0; i < nodeList.getLength(); i++) {
            String urlPattern = nodeList.item(i).getTextContent().trim();
            if (IdsConst.ANON_ACCESS_POLICY.equals(policy)) {
                this.addAnonUrl(urlPattern);
            }
            if (IdsConst.AUTH_ACCESS_POLICY.equals(policy)) {
                this.addAuthUrl(urlPattern);
            }
            if (IdsConst.ROUTER_ACCESS_POLICY.equals(policy)) {
                this.addRouterUrl(urlPattern);
            }
        }
    }

}
